package com.xu.redis.service;

import com.xu.redis.sequence.ISequenceRule;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 序列号生成工具
 *
 * @Author: 许乾伟
 * @Date: 2024/3/22 13:48
 */
@Component
public class SequenceService {
    /**
     * 永久key
     */
    final String REDIS_KEY_FORMAT="%s_sequence_counter";
    /**
     * 按天重置key
     */
    final String REDIS_KEY_DAY_FORMAT="%s_%s_sequence_counter";
    /**
     * 位数不足前面补0
     */
    final String COUNTER_FORMAT="%%0%dd";
    @Resource(name = "newRedisTemplate")
    private RedisTemplate redisTemplate;

    /**
     * 生成一个自动编号
     * @param rule
     * @return
     */
    public String generateCode(ISequenceRule rule) {
        synchronized (this) {
            // nums位数字，不够的前面补0
            String format = String.format(COUNTER_FORMAT, rule.length());
            // 返回拼接好的编号
            return rule.prefix() + String.format(format, getIncrement(rule));
        }
    }
    /**
     * 生成一个按天重置计数器的自动编号
     * @param rule 编号规则枚举
     * @return 自动生成的编号
     */
    public String generateDayResetCode(ISequenceRule rule) {
        synchronized (this) {
            if (StringUtils.isEmpty(rule.pattern())){
                throw new RuntimeException("必须配置序列号规则的patter字段");
            }
            // nums位数字，不够的前面补0
            String format = String.format(COUNTER_FORMAT, rule.length());
            String dateFormat = DateTimeFormatter.ofPattern(rule.pattern()).format(LocalDateTime.now());
            // 返回拼接好的编号
            return rule.prefix() + dateFormat +
                    // redisKey组成: 前缀，确保每天都是新的key，编号从0001开始
                    String.format(format, getDsyResetIncrement(rule));
        }
    }
    /**
     * 从redis中获取一个计数器,并按天重置
     * @param rule 编号规则枚举
     * @return 计数器
     */
    private Integer getDsyResetIncrement(ISequenceRule rule) {
        String dateFormat = DateTimeFormatter.ofPattern(rule.pattern()).format(LocalDateTime.now());
        String redisKey = String.format(REDIS_KEY_DAY_FORMAT,rule.prefix(),dateFormat);

        if (redisTemplate.hasKey(redisKey)) {
            return redisTemplate.opsForValue().increment(redisKey).intValue();
        } else {
            //清空前一天的计数器
            String nextDateFormat = DateTimeFormatter.ofPattern(rule.pattern()).format(LocalDateTime.now().minusDays(1));
            String nextRedisKey = String.format(REDIS_KEY_DAY_FORMAT, nextDateFormat, rule.prefix());
            redisTemplate.delete(nextRedisKey);
            redisTemplate.opsForValue().setIfAbsent(redisKey, 1);
            return 1;
        }
    }

    /**
     * 从redis中获取一个计数器
     * @param rule
     * @return
     */
    private Integer getIncrement(ISequenceRule rule) {
        String redisKey = String.format(REDIS_KEY_FORMAT,rule.prefix());
        if (redisTemplate.hasKey(redisKey)) {
            return redisTemplate.opsForValue().increment(redisKey).intValue();
        } else {
            redisTemplate.opsForValue().setIfAbsent(redisKey, 1);
            return 1;
        }
    }
}
